package ldh.im.fxbase.util;

import com.jfoenix.controls.JFXButton;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Bounds;
import javafx.geometry.NodeOrientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.kordamp.ikonli.javafx.FontIcon;

import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RegionUtil {

//    private final static Logger LOGGER = LoggerUtil.getFileLogger(RegionUtil.class);
    private final static Logger LOGGER = Logger.getLogger(RegionUtil.class.getName());

    public static Node copyGraphic(Node node) {
        if (node == null) return null;
        if (node instanceof FontIcon) {
            FontIcon fontIcon = (FontIcon) node;
            if (fontIcon.getIconCode() != null) {
                return FontIcon.of(((FontIcon) node).getIconCode());
            }
        }
        return null;
    }

    public static void loadFxml(Pane pane, Object controller, String urlFxml) {
        FXMLLoader fxmlLoader = new FXMLLoader(RegionUtil.class.getResource(urlFxml));
        fxmlLoader.setController(controller);
        fxmlLoader.setRoot(pane);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            LOGGER.log(Level.SEVERE, "loadFxml error", exception);
            throw new RuntimeException(exception);
        }
    }

    public static <T> T loadFxml(URL url) {
        FXMLLoader fxmlLoader = new FXMLLoader(url);
        try {
            return fxmlLoader.load();
        } catch (IOException exception) {
            LOGGER.log(Level.SEVERE, "loadFxml error", exception);
            throw new RuntimeException(exception);
        }
    }

    public static <N, T> FxmlBean<N, T> loadFxmlBean(URL url) {
        FXMLLoader fxmlLoader = new FXMLLoader(url);
        try {
            N t = fxmlLoader.load();
            T t1 = fxmlLoader.getController();
            return new FxmlBean(t1, t);
        } catch (IOException exception) {
            LOGGER.log(Level.SEVERE, "loadFxmlBean error", exception);
            throw new RuntimeException(exception);
        }
    }

    public static void sizeRegion(Region region, Scene scene) {
        region.setPrefWidth(scene.getWidth());
        region.setPrefHeight(scene.getHeight());
//        region.resize(scene.getWidth(), scene.getHeight());
        region.requestLayout();
    }

    public static void sizeRegionWhenSceneChange(Region region, Scene scene) {
        scene.widthProperty().addListener((l, o, n)-> RegionUtil.sizeRegion(region, scene));
        scene.heightProperty().addListener((l, o, n)->RegionUtil.sizeRegion(region, scene));
    }

    public static Double anchorY(Region node, PopupPos popupPos) {
        double anchorY = node.getScene().getWindow().getY() + node.localToScene(0, 0).getY() + node.getScene().getY();
        if (popupPos == PopupPos.down_east) {
            anchorY = anchorY + node.getHeight();
        } else if (popupPos == PopupPos.down_west) {
            anchorY = anchorY + node.getHeight();
        } else if (popupPos == PopupPos.up_east) {
            anchorY = anchorY - node.getHeight();
        } else if (popupPos ==PopupPos.up_west) {
            anchorY = anchorY - node.getHeight();
        }
        return anchorY;
    }

    public static Double anchorX(Region node, PopupPos popupPos) {
        double anchorX = node.getScene().getWindow().getX() + node.localToScene(0, 0).getX() + node.getScene().getX() - 1;
        if (popupPos == PopupPos.down_east) {
            anchorX = anchorX + node.getHeight();
        } else if (popupPos == PopupPos.down_west) {
            anchorX = anchorX + node.getHeight();
        } else if (popupPos == PopupPos.up_east) {
            anchorX = anchorX - node.getWidth();
        } else if (popupPos == PopupPos.up_west) {
            anchorX = anchorX - node.getWidth();
        }
        return anchorX;
    }

    public static Double anchorX(Region node) {
        double anchorX = node.getScene().getWindow().getX() + node.localToScene(0, 0).getX() + node.getScene().getX();
        return anchorX;
    }

    public static Double anchorY(Region node) {
        double anchorY = node.getScene().getWindow().getY() + node.localToScene(0, 0).getY() + node.getScene().getY();
        return anchorY;
    }

    public static double calcAnchorX(Region region, PopupPos popupPos, Node contentPane) {
        return calcAnchorX(region, popupPos, contentPane, -1d);
    }

    public static double calcAnchorX(Region region, PopupPos popupPos, Node contentPane, double cpwidth) {
        double anchorX = region.getScene().getWindow().getX() + region.localToScene(0, 0).getX() + region.getScene().getX();
        double width = popupContentWidth(contentPane);
        double cwidth = cpwidth <= 0 ? popupContentWidth(contentPane) : cpwidth;

        if (region.getParent() != null && region.getParent().getNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) {
            if (popupPos == PopupPos.down_east) {
                anchorX = anchorX + region.getWidth() - cwidth;
            } else if (popupPos == PopupPos.down_west) {
                anchorX = anchorX - width;
            } else if (popupPos == PopupPos.up_east) {
                anchorX = anchorX + region.getWidth() - cwidth;
            } else if (popupPos == PopupPos.up_west) {
                anchorX = anchorX - width;
            }
        } else {
            if (popupPos == PopupPos.down_east) {
//            anchorX = anchorX + region.getWidth() - popupContentWidth(contentPane);
            } else if (popupPos == PopupPos.down_west) {
                anchorX = anchorX + region.getWidth() - width;
            } else if (popupPos == PopupPos.up_east) {
//            anchorX = anchorX - popupContentWidth(contentPane);
                anchorX = anchorX + region.getWidth();
            } else if (popupPos == PopupPos.up_west) {
                anchorX = anchorX - width;
            }
        }

        return anchorX;
    }

    public static double calcAnchorY(Region region, PopupPos popupPos, Node contentPane) {
        return calcAnchorY(region, popupPos, contentPane, -1d);
    }

    public static double calcAnchorY(Region region, PopupPos popupPos, Node contentPane, double cpheight) {
        double anchorY = region.getScene().getWindow().getY() + region.localToScene(0, 0).getY() + region.getScene().getY();
        double cheight = cpheight <= 0 ? popupContentHeight(contentPane) : cpheight;

        if (popupPos == PopupPos.down_east) {
            anchorY = anchorY + region.getHeight() + 1;
        } else if (popupPos == PopupPos.down_west) {
            anchorY = anchorY + region.getHeight() + 1;
        } else if (popupPos == PopupPos.up_east) {
            anchorY = anchorY - cheight - 1;
        } else if (popupPos == PopupPos.up_west) {
            anchorY = anchorY - cheight - 1;
        }
        return anchorY;
    }

    public static double snapSize(Region region, double value) {
        return snapSize(value, region.isSnapToPixel());
    }

    private static double popupContentWidth(Node contentPane) {
        if (contentPane instanceof Region) {
            Region r = (Region) contentPane;
            return Math.max(r.getWidth(), r.getPrefWidth());
        }
        return contentPane.prefWidth(0);
    }

    private static double popupContentHeight(Node contentPane) {
        if (contentPane instanceof Region) {
            Region r = (Region) contentPane;
            return Math.max(r.getHeight(), r.getPrefHeight());
        }
        return contentPane.prefHeight(0);
    }

    private static double snapSize(double value, boolean snapToPixel) {
        return snapToPixel ? Math.ceil(value) : value;
    }

    public static class FxmlBean<N, T> {

        private T controller;

        private N node;

        public FxmlBean(T controller, N node) {
            this.node = node;
            this.controller = controller;
        }

        public T getController() {
            return controller;
        }

        public N getNode() {
            return node;
        }
    }

    public static double calcStringHeight(String str, double width) {
        Text textHolder = new Text();
        textHolder.setWrappingWidth(width);
        textHolder.setText(str);
        double h = textHolder.layoutBoundsProperty().get().getHeight();
        return h;
    }

    public static double calcStringWidth(String str) {
        Text textHolder = new Text();
        textHolder.setText(str);
        double w = textHolder.layoutBoundsProperty().get().getWidth();
        return w;
    }

    public static void centerNodeInScrollPane(ScrollPane scrollPane, Node node) {
        double h = scrollPane.getContent().getBoundsInLocal().getHeight();
        double y = (node.getBoundsInParent().getMaxY() +
                node.getBoundsInParent().getMinY()) / 2.0;
        double v = scrollPane.getViewportBounds().getHeight();
        scrollPane.setVvalue(scrollPane.getVmax() * ((y - 0.5 * v) / (h - v)));
    }

    public static void anchor(Node node, double top, double right, double bottom, double left) {
        AnchorPane.setTopAnchor(node, top);
        AnchorPane.setRightAnchor(node, right);
        AnchorPane.setBottomAnchor(node, bottom);
        AnchorPane.setLeftAnchor(node, left);
    }

    public static void anchorTopLeft(Node node, double top, double left) {
        AnchorPane.setTopAnchor(node, top);
        AnchorPane.setLeftAnchor(node, left);
    }

    public static JFXButton createButton(String title, EventHandler<ActionEvent> eventHandler) {
        JFXButton button = new JFXButton(title);
        button.setOnAction(eventHandler);
        return button;
    }

    public static boolean nodeIsVisibleArea(Node node) {
        Bounds boundsInWindow = node.localToScene(node.getBoundsInParent());
        // 判断是否在窗口可视区域内
        if (node.getScene() != null && node.getScene().getWindow() != null) {
            boolean isVisibleInWindow = boundsInWindow.intersects(node.getScene().getWindow().getX(),
                    node.getScene().getWindow().getY(),
                    node.getScene().getWindow().getWidth(),
                    node.getScene().getWindow().getHeight());
            return isVisibleInWindow;
        }
        return false;
    }
}
